package com.cwz.datasource.dynamic.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.cwz.core.context.DataSourceContextHolder;
import com.cwz.core.exception.datasource.DataSourceException;
import com.cwz.core.utils.spring.SpringUtils;
import com.cwz.core.utils.string.StringUtils;
import com.cwz.datasource.dynamic.model.DynamicUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

/**
 * @program: w-demo
 * @description: 动态数据源实现类
 * @author: Wen
 **/
@Slf4j
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
	/**
	 * 【核心】动态数据源维护的所有数据源信息
	 *  备注：Spring 维护的所有数据源，实际上放在了 AbstractRoutingDataSource 抽象类中的 targetDataSources 属性中
	 * 	但是可能是出于安全考虑，AbstractRoutingDataSource 只提供了 setTargetDataSources 的方法，却没有提供 getTargetDataSources 的方法
	 * 	这带来了非常大的不便，于是我们在这个子类中单独定义一个私有属性，并额外提供一个 getTargetDataSources 的方法
	 *  而 setTargetDataSources 本质上仍然是调用父级的。
	 **/
	private Map<Object, Object> targetDataSources;

	@Override
	public void setTargetDataSources(Map<Object, Object> targetDataSources) {
		this.targetDataSources = targetDataSources;
		super.setTargetDataSources(targetDataSources);
	}

	public Map<Object, Object> getTargetDataSources() {
		return this.targetDataSources;
	}

	@Override
	protected DataSource determineTargetDataSource() {
		DruidDataSource dataSource = null;
		super.setLenientFallback(false);
		boolean needReInit = false;
		try {
			dataSource = (DruidDataSource) super.determineTargetDataSource();
		} catch (IllegalStateException e) {
			needReInit = true;
		}

		if (needReInit) {
			String company = DataSourceContextHolder.get();
			DynamicDataSourceInit dynamicDataSourceInit = SpringUtils.getBean("dynamicDataSourceInit");
			DruidDataSource baseDatasource = (DruidDataSource) targetDataSources.get("baseDatasource");
			Connection conn = null;
			List<DynamicUser> dynamicUser = null;
			try {
				conn = baseDatasource.getConnection();
				dynamicUser = dynamicDataSourceInit.getDynamicUser(conn, company);
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					if (conn != null && !conn.isClosed()) {
						conn.close();
					}
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (StringUtils.isNotEmpty(dynamicUser)) {
				dynamicDataSourceInit.init();
				return super.determineTargetDataSource();
			} else {
				log.error("数据库不存在 company = {} 的数据信息", company);
				throw new DataSourceException("数据库出错，请联系管理员");
			}
		}
		return dataSource;
	}

	@Override
	protected Object determineCurrentLookupKey() {
		String company = DataSourceContextHolder.get();
		return StringUtils.isNotBlank(company) ? company : "baseDatasource";
	}
}
